import os
import json

import os
import sys

# 获取当前脚本所在目录
current_dir = os.path.dirname(os.path.abspath(__file__))
# 获取项目根目录
project_root = os.path.dirname(os.path.dirname(current_dir))

# 将项目根目录添加到 sys.path
sys.path.append(project_root)

from typing import Dict, List, Optional, Set
from datetime import datetime, timedelta
from decimal import Decimal
from vnpy.trader.engine import BaseEngine
from vnpy.event import EventEngine, Event, EVENT_TIMER  # 只导入vnpy的事件
from vnpy.trader.engine import MainEngine
from vnpy.trader.constant import Direction, Exchange, Interval
from vnpy.trader.object import TradeData, OrderData, BarData, TickData
from vnpy.trader.database import get_database
from portfolio_trader.strategy.template import StrategyTemplate, StrategyEngine
from portfolio_trader.advisor.engine import AdvisorEngine, AdvisorTemplate
from portfolio_trader.advisor.StrategyAdvisor import StrategyAdvisor
from portfolio_trader.event import EVENT_PORTFOLIO_UPDATE  # 从我们自己的模块导入事件类型
import tushare as ts
from portfolio_trader.datafeed.data_loader import PortfolioDataLoader
from portfolio_trader.engine.asset_manager import AssetManager
from portfolio_trader.engine.position_manager import PositionManager
from portfolio_trader.engine.stock_collection_manager import StockCollection
from portfolio_trader.engine.trade_recorder import TradeRecorder
from portfolio_trader.signal.signal_manager import SignalManager
from portfolio_trader.signal.signal_result import SignalResult

APP_NAME = "PortfolioEngine"


class PortfolioEngine(BaseEngine):
    """
    投资组合交易引擎
    """
    def __init__(self, main_engine: MainEngine, event_engine: EventEngine):
        """构造函数"""
        super().__init__(main_engine, event_engine, APP_NAME)
        
        # 数据库
        self.database = get_database()
        
        # 初始化数据加载器
        self.data_loader = PortfolioDataLoader()

        # 初始化Tushare API
        tushare_token = "7a61f9d4ee18ecaa09559a5034dac045580a8a4c8abef8a483aa39e9"
        if not self.data_loader.init(tushare_token):
            print("Tushare API初始化失败")
            return
        
        # 初始化资产管理器和持仓管理器
        self.asset_manager = AssetManager()
        self.position_manager = PositionManager(self.asset_manager)
        self.position_manager.data_loader = self.data_loader  # 传递data_loader实例
        
        # 初始化股票收藏管理器
        self.stock_collection_manager = StockCollection(self.data_loader)
        
        # 初始化引擎
        self.advisor_engine = AdvisorEngine()
        self.strategy_engine = StrategyEngine()
        
        # 初始化交易记录器
        self.trade_recorder = TradeRecorder()
        
        # 初始化信号管理器
        self.signal_manager = SignalManager(self.position_manager)
        self.signal_manager.init(tushare_token)  # 初始化Tushare token
        
        # 添加数据相关属性
        self.symbols = set(self.stock_collection_manager.collection)  # 使用股票收藏管理器的收藏列表初始化
        self.last_update_time: datetime = None  # 最后数据更新时间
        self.update_interval: timedelta = timedelta(days=1)  # 数据更新间隔
        self.data_file = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "portfolio_trader", "data", "portfolio_data.json")
        
        # 加载持久化数据
        self.load_data()
        
        # 确保last_update_time被正确初始化
        if self.last_update_time is None:
            self.last_update_time = datetime.now() - timedelta(days=1)  # 默认设置为前一天
            print(f"使用默认的最后更新时间: {self.last_update_time}")
        
        self.asset_manager.set_last_update_time(self.last_update_time)

        # 初始化策略顾问
        self.advisor = StrategyAdvisor(self.asset_manager, self.position_manager, self.stock_collection_manager)
        self.advisor.data_loader = self.data_loader  # 传递data_loader实例
        self.advisor.collection = self.stock_collection_manager.collection  # 使用股票收藏管理器的收藏列表
        self.advisor_engine.advisors["StrategyAdvisor"] = self.advisor

        # 注册事件处理
        # self.register_event()
        # 更新市场数据
        self.update_market_data()
        # 更新账户信息
        self.update_account()
        
    def register_event(self):
        """注册事件监听"""
        self.event_engine.register(EVENT_TIMER, self.process_timer_event)
        
    def process_timer_event(self, event: Event):
        """处理定时事件"""
        # 更新市场数据
        self.update_market_data()
        # 更新账户信息
        self.update_account()
        # 发送更新事件
        event = Event(type=EVENT_PORTFOLIO_UPDATE)
        self.event_engine.put(event)
        
    def update_market_data(self) -> None:
        """更新市场数据"""
        current_time = datetime.now()
        # 检查是否需要更新
        if (self.last_update_time and 
            current_time - self.last_update_time < self.update_interval):
            # 未达到更新时间间隔，不更新
            return
            
        # 更新每个股票的数据
        for symbol in self.symbols:
            try:
                # 更新本地数据
                self.data_loader.update_daily_data(symbol, current_time)
                
                # 更新估值数据
                self.data_loader.update_valuation_data(symbol, current_time)

            except Exception as e:
                print(f"更新{symbol}数据失败: {str(e)}")
        
        # 调用position_manager的update_market_data方法更新持仓市场数据
        self.position_manager.update_market_data()
                
        self.last_update_time = current_time
        # 更新子模块的最后更新时间
        self.asset_manager.set_last_update_time(current_time)
        
        # 保存更新时间到文件
        
        self.save_data()
        
    def _convert_df_to_bars(self, df, symbol: str) -> List[BarData]:
        """将DataFrame转换为BarData列表"""
        bars = []
        for _, row in df.iterrows():
            bar = BarData(
                symbol=symbol,
                exchange=self.data_loader._get_exchange(symbol),
                datetime=datetime.strptime(row['trade_date'], '%Y%m%d'),
                interval=Interval.DAILY,
                open_price=float(row['open']),
                high_price=float(row['high']),
                low_price=float(row['low']),
                close_price=float(row['close']),
                volume=float(row['vol']),
                turnover=float(row['amount']),
                gateway_name="TUSHARE"
            )
            bars.append(bar)
        return bars

    def update_account(self):
        """更新账户信息"""
        # 从position_manager获取持仓信息
        positions = self.position_manager.get_positions()
        market_value = sum(pos["volume"] * pos.get("current_price", pos["cost"]) for pos in positions.values())
        
        # 从asset_manager获取账户信息并更新
        account = self.asset_manager.get_account()
        account.update({
            "market_value": market_value,
            "total_asset": account["available"] + market_value,
            "daily_pnl": sum(pos.get("daily_pnl", 0) for pos in positions.values())
        })
        self.asset_manager.update_account(account)
        
        # 更新advisor_engine的账户和持仓信息
        self.advisor_engine.update_account(account, positions)
        
    def generate_signals(self, strategy_name: str = "BollChannel", days: int = 30) -> Dict[str, List[SignalResult]]:
        """为投资组合生成交易信号
        
        参数:
            strategy_name (str): 策略名称
            days (int): 回溯天数
            
        返回:
            Dict[str, List[SignalResult]]: 股票代码到信号列表的映射
        """
        return self.signal_manager.generate_signals_for_portfolio(strategy_name, days)
    
    def get_latest_signals(self, strategy_name: str = "BollChannel") -> Dict[str, SignalResult]:
        """获取投资组合的最新交易信号
        
        参数:
            strategy_name (str): 策略名称
            
        返回:
            Dict[str, SignalResult]: 股票代码到最新信号的映射
        """
        return self.signal_manager.get_latest_signals_for_portfolio(strategy_name)
    
    def get_signal_summary(self, strategy_name: str = "BollChannel") -> Dict[str, Dict]:
        """获取信号摘要
        
        参数:
            strategy_name (str): 策略名称
            
        返回:
            Dict[str, Dict]: 股票代码到信号摘要的映射
        """
        return self.signal_manager.get_signal_summary(strategy_name)
        
    def buy(self, symbol: str, price: float, volume: int, commission_rate: float = 0.0001) -> str:
        """买入
        :param commission_rate: 手续费率，默认万分之一
        """
        result = self.position_manager.buy(symbol, price, volume, commission_rate)
        if result == "Success":
            # 记录交易
            name = self.data_loader.get_stock_name(symbol)
            amount = price * volume
            self.trade_recorder.record_trade(
                symbol=symbol,
                name=name,
                order_price=price,
                trade_price=price,
                volume=volume,
                direction="buy",
                amount=amount,
                commission = amount * commission_rate  # 万分之一手续费
            )
            self.save_data()
        return result
        
    def sell(self, symbol: str, price: float, volume: int, commission_rate: float = 0.0001) -> bool:
        """卖出
        :param commission_rate: 手续费率，默认万分之一
        """
        result = self.position_manager.sell(symbol, price, volume, commission_rate)
        if result:
            # 记录交易
            name = self.data_loader.get_stock_name(symbol)
            amount = price * volume
            self.trade_recorder.record_trade(
                symbol=symbol,
                name=name,
                order_price=price,
                trade_price=price,
                volume=volume,
                direction="sell",
                amount=amount,
                commission=amount * commission_rate  # 万分之一手续费
            )
            self.save_data()
        return result
        
    def adjust_capital(self, amount: float) -> bool:
        """调整资金"""
        result = False
        if amount > 0:
            result = self.asset_manager.deposit(amount)
        else:
            result = self.asset_manager.withdraw(abs(amount))
        if result:
            self.save_data()
        return result

    def save_data(self) -> None:
        """保存数据到JSON文件"""
        data = {
            "account": self.asset_manager.save(),
            "positions": self.position_manager.save_data(),
            "trades": self.trade_recorder.save_data(),
            "last_update_time": self.last_update_time.strftime('%Y-%m-%d %H:%M:%S') if self.last_update_time else None
        }
        try:
            with open(self.data_file, 'w') as f:
                json.dump(data, f, indent=4)
        except Exception as e:
            print(f"保存数据失败: {str(e)}")
            
    def load_data(self) -> None:
        """从JSON文件加载数据"""
        try:
            with open(self.data_file, 'r') as f:
                data = json.load(f)
                # 加载账户数据
                if "account" in data:
                    self.asset_manager.load(data["account"])
                # 加载持仓数据
                if "positions" in data:
                    self.position_manager.load_data(data["positions"])
                if "trades" in data:
                    self.trade_recorder.load_data(data["trades"])
                # 加载最后更新时间
                if "last_update_time" in data and data["last_update_time"]:
                    try:
                        self.last_update_time = datetime.strptime(data["last_update_time"], '%Y-%m-%d %H:%M:%S')
                        print(f"读取数据成功，最后更新时间: {self.last_update_time}")
                    except ValueError as e:
                        print(f"日期格式错误: {str(e)}")
                        self.last_update_time = None
        except (FileNotFoundError, json.JSONDecodeError) as e:
            print(f"读取数据文件失败: {str(e)}")
            self.last_update_time = None
        
    def add_strategy(self, name: str, strategy: StrategyTemplate):
        """添加策略"""
        self.strategy_engine.add_strategy(name, strategy)
        
    def get_strategy_signal(self, name: str) -> Dict:
        """获取策略信号"""
        return self.strategy_engine.get_signal(name)
        
    def add_advisor(self, name: str, advisor: AdvisorTemplate):
        """添加投资建议生成器"""
        self.advisor_engine.add_advisor(name, advisor)
        
    def get_advice(self, name: str) -> Dict:
        """获取投资建议"""
        return self.advisor_engine.get_advice(name)

    @property
    def total_asset(self) -> float:
        """总资产"""
        return self.asset_manager.get_account()["total_asset"]
        
    @property
    def available_capital(self) -> float:
        """可用资金"""
        return self.asset_manager.get_account()["available"]
        
    @property
    def market_value(self) -> float:
        """持仓市值"""
        return self.asset_manager.get_account()["market_value"]
        
    @property
    def daily_pnl(self) -> float:
        """当日盈亏"""
        return self.asset_manager.get_account()["daily_pnl"]

    def add_symbol(self, symbol: str) -> None:
        """添加关注的股票"""
        self.stock_collection_manager.add_to_collection(symbol)
        self.symbols = set(self.stock_collection_manager.collection)
        
    def remove_symbol(self, symbol: str) -> None:
        """移除关注的股票"""
        self.stock_collection_manager.remove_from_collection(symbol)
        self.symbols = set(self.stock_collection_manager.collection)

    def init_datafeed(self, tushare_token: str) -> bool:
        """初始化数据源"""
        return self.data_loader.init(tushare_token)


# def main():
#     """测试主函数"""
#     from vnpy.event import EventEngine
#     from vnpy.trader.engine import MainEngine
    
#     # 创建事件引擎和主引擎
#     event_engine = EventEngine()
#     main_engine = MainEngine(event_engine)
    
#     # 创建投资组合引擎
#     portfolio_engine = PortfolioEngine(main_engine, event_engine)
    
#     # 更新市场数据
#     portfolio_engine.update_market_data()
    
#     portfolio_engine.buy("000001", 10.21, 1000)
#     portfolio_engine.buy("600004", 8.86, 1000)
#     portfolio_engine.buy("600519", 1565.94, 1000)
#     portfolio_engine.buy("000858", 131.75, 1000)
    
#     # 查看账户信息
#     # account = portfolio_engine.asset_manager.get_account()
#     # print("\n账户信息:")
#     # print(f"总资产: {account['total_asset']}")
#     # print(f"可用资金: {account['available']}")
#     # print(f"持仓市值: {account['market_value']}")
#     # print(f"当日盈亏: {account['daily_pnl']}")
    
#     # 查看持仓信息
#     positions = portfolio_engine.position_manager.get_positions()
#     print("\n持仓信息:")
#     for symbol, pos in positions.items():
#         print(f"股票代码: {symbol}")
#         print(f"持仓数量: {pos['volume']}")
#         print(f"持仓成本: {pos['cost']}")
#         print(f"当前价格: {pos['current_price']}")
#         print(f"持仓市值: {pos['market_value']}")
#         print(f"总盈亏: {pos['pnl']}")
#         print(f"盈亏比例: {pos['pnl_pct']}%")
    
#     # 打印交易记录
#     # print("\n交易记录:")
#     # trades = portfolio_engine.trade_recorder.get_trades()
#     # for trade in trades:
#     #     print(trade)

#     # 测试量化信号模块
#     print("\n测试量化信号模块:")
#     # 为持仓股票生成量化信号

#     # signals = portfolio_engine.signal_manager.generate_signals_for_portfolio(strategy_name="AtrRsi", days=365)
#     # print(f"生成信号数量: {sum(len(signal_list) for signal_list in signals.values())}")
    
#     # 获取最新信号摘要
#     signal_summary = portfolio_engine.signal_manager.get_signal_summary(strategy_name="AtrRsi")
#     print("\n信号摘要:")
#     for symbol, summary in signal_summary.items():
#         print(f"股票代码: {symbol}")
#         print(f"策略: {summary['strategy']}")
#         print(f"时间: {summary['datetime']}")
#         print(f"操作: {summary['action']}")
#         print(f"价格: {summary['price']}")
#         print(f"数量: {summary['volume']}")
#         print(f"信号类型: {summary['signal_type']}")
#         print()

#     # 生成投资建议
#     # advice = portfolio_engine.advisor.generate_advice_for_stock("600000", strategies=[ "AtrRsiStrategy"])
#     # print(advice)
#     positions = portfolio_engine.position_manager.get_positions()

#     for symbol, pos in positions.items():
#         print(symbol)
#         advice = portfolio_engine.advisor.generate_advice_for_stock(symbol=symbol, strategies=[ "AtrRsiStrategy"])
#         print("\n投资建议:")
#         print(advice.get('decisions'))

# if __name__ == "__main__":
#     main()

def main():
    """测试主函数"""
    from vnpy.event import EventEngine
    from vnpy.trader.engine import MainEngine
    
    # 创建事件引擎和主引擎
    event_engine = EventEngine()
    main_engine = MainEngine(event_engine)
    
    # 创建投资组合引擎
    portfolio_engine = PortfolioEngine(main_engine, event_engine)
    
    # 更新市场数据
    portfolio_engine.update_market_data()
    
    # portfolio_engine.buy("000001", 10.21, 1000)
    # portfolio_engine.buy("600004", 8.86, 1000)
    # portfolio_engine.buy("600519", 1565.94, 1000)
    # portfolio_engine.buy("000858", 131.75, 1000)
    
    # 查看账户信息
    # account = portfolio_engine.asset_manager.get_account()
    # print("\n账户信息:")
    # print(f"总资产: {account['total_asset']}")
    # print(f"可用资金: {account['available']}")
    # print(f"持仓市值: {account['market_value']}")
    # print(f"当日盈亏: {account['daily_pnl']}")
    

    # 查看持仓信息
    positions = portfolio_engine.position_manager.get_positions()
    print("\n持仓信息:")
    for symbol, pos in positions.items():
        print(f"股票代码: {symbol}")
        print(f"持仓数量: {pos['volume']}")
        print(f"持仓成本: {pos['cost']}")
        print(f"当前价格: {pos['current_price']}")
        print(f"持仓市值: {pos['market_value']}")
        print(f"总盈亏: {pos['pnl']}")
        print(f"盈亏比例: {pos['pnl_pct']}%")

    # 打印交易记录
    # print("\n交易记录:")
    # trades = portfolio_engine.trade_recorder.get_trades()
    # for trade in trades:
    #     print(trade)

    # 测试量化信号模块
    # print("\n测试量化信号模块:")
    # # 为持仓股票生成量化信号

    # results = portfolio_engine.signal_manager.get_latest_trading_day_signals()

    # for result in results.items():
    #     print(result)

    # strategy_name = "AtrRsi"
    # 生成信号
    # signals = portfolio_engine.signal_manager.generate_signals_for_portfolio(strategy_name=strategy_name, days=30)
    # print(f"生成信号数量: {sum(len(signal_list) for signal_list in signals.values())}")
    
    # # 获取最新信号摘要
    # signal_summary = portfolio_engine.signal_manager.get_signal_summary(strategy_name=strategy_name)
    # print("\n信号摘要:")
    # for symbol, summary in signal_summary.items():
    #     print(f"股票代码: {symbol}")
    #     print(f"策略: {summary['strategy_name']}")
    #     print(f"时间: {summary['datetime']}")
    #     print(f"信号类型: {summary['signal_type']}")
    #     print(f"价格: {summary['price']}")
    #     print(f"数量: {summary['volume']}")
    #     print()

    
    
    # 测试不同类型的信号
    # from portfolio_trader.signal.signal_result import SignalResult, SignalType
    
    # # 创建测试信号
    # test_signals = {}
    # for symbol in positions.keys():
    #     # 买入信号
    #     buy_signal = SignalResult(symbol, strategy_name)
    #     buy_signal.set_buy_signal(price=positions[symbol].get("current_price", 100.0))
        
    #     # 卖出信号
    #     sell_signal = SignalResult(symbol, strategy_name)
    #     sell_signal.set_sell_signal(price=positions[symbol].get("current_price", 100.0))
        
    #     # 持仓信号
    #     hold_signal = SignalResult(symbol, strategy_name)
    #     hold_signal.set_hold_signal()
        
    #     test_signals[symbol] = [buy_signal, sell_signal, hold_signal]
    
    # # 打印测试信号
    # print("\n测试不同类型的信号:")
    # for symbol, signal_list in test_signals.items():
    #     print(f"\n股票代码: {symbol}")
    #     for signal in signal_list:
    #         print(f"信号类型: {signal.signal_type.value}, 描述: {signal}")
    #         print(f"信号字典: {signal.to_dict()}")
    #         print()
    # 生成收藏列表中所有股票的投资建议
    # advice_collection = portfolio_engine.advisor.generate_advice_for_collection(
    #     strategies=[ "AtrRsiStrategy"],
    # )

    # # 打印每个股票的投资建议（JSON 格式）
    # for symbol, advice in advice_collection.items():
    #     print(f"\n=== {symbol} 的投资建议 ===")
    #     print(json.dumps(advice, indent=4, ensure_ascii=False,cls=DecisionEncoder))
    
    # 生成投资建议
    
    # import time
    # for symbol, pos in positions.items():
    #     print(symbol)
    #     advice = portfolio_engine.advisor.generate_advice_for_stock(symbol=symbol, strategies=[ "AtrRsiStrategy"])
    #     if advice:
    #         print("\n投资建议:")
    #         print(advice.get('decisions'))
    #     else:   
    #         print(f"没有生成{symbol}投资建议")
    #         time.sleep(5)
    advice_for_one = portfolio_engine.advisor.generate_advice_for_stock("600000", strategies=[ "AtrRsiStrategy"])
    advice_for_collection = portfolio_engine.advisor.generate_advice_for_collection(strategies=[ "AtrRsiStrategy"])

    print("调用generate_advice_for_stock的返回值")
    print(advice_for_one)
    print("调用generate_advice_for_collection的返回值")
    print(advice_for_collection)

    advice_for_one = portfolio_engine.advisor.generate_advice_for_stock("600004", strategies=[ "AtrRsiStrategy"])
    # advice_for_collection = portfolio_engine.advisor.generate_advice_for_collection(strategies=[ "AtrRsiStrategy"])
    print("调用generate_advice_for_stock的返回值")
    print(advice_for_one)
    # print("调用generate_advice_for_collection的返回值")
    # print(advice_for_collection)
if __name__ == "__main__":
    main()
